package models

import (
	"bytes"
	"fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/util"
	"io"
	"os"
	"time"
)

type Image struct{}

type UploadImageRQ struct {
	MbrId   ID     `json:"-"`
	Proto   int    `json:"proto"`
	Type    int    `json:"type"`
	Seq     int    `json:"seq"`
	Data    []byte `json:"-"`
	RootDir string `json:"-"`
	Ext     string `json:"-"`
	Cdn     string `json:"-"`
}

var fuzzy_map = map[string]string{
	"0_0": "opdio", //member photo
	"1_1": "aizkl", //member/card_fs
	"1_2": "colwk", //member/card_rs
	"2_1": "erwlk", //carrier_owner/vehicle
	"2_2": "wkmal", //carrier_owner/driving_license
	"2_3": "pkaie", //carrier_owner/vehicle_license_1
	"2_4": "wqkeo", //carrier_owner/vehicle_license_2
	"3_1": "valeq", //cargo_owner/biz_license
	"4_1": "zceqb", //logistics_emp/biz_license
	"4_2": "yqqkd", //logistics_emp/biz_permit
}

type Command interface {
	Exec() (string, error)
}

type uploadAuthImgCmd struct {
	*UploadImageRQ
}

type uploadAdImgCmd struct {
	*UploadImageRQ
}

func InitImageDir(dir string) {
	createDirIfNotExists(fmt.Sprintf("%sauth/", dir))
	createDirIfNotExists(fmt.Sprintf("%sad/", dir))
}

func (i Image) Upload(rq *UploadImageRQ) (string, error) {
	return getCmd(rq).Exec()
}

func (u *uploadAuthImgCmd) Exec() (url string, err error) {
	err = u.save(u.UploadImageRQ)
	if err != nil {
		util.GetLogger().Error("[model-uploadimage] - error: %s", err.Error())
		err = errors.New(errors.MSG_Image_Upload_Error)
	} else {
		url, err = u.updateUrl(u.UploadImageRQ)
		if err != nil {
			util.GetLogger().Error("[model-uploadimage] - error: %s", err.Error())
		}
	}
	return
}

func createDirIfNotExists(dir string) {
	if _, err := os.Stat(dir); err != nil {
		if os.IsNotExist(err) {
			os.MkdirAll(dir, 0777)
		}
	}
}

func getCmd(rq *UploadImageRQ) (cmd Command) {
	if rq.Type == 5 {
		return &uploadAdImgCmd{rq}
	} else {
		return &uploadAuthImgCmd{rq}
	}

}

func (u *uploadAuthImgCmd) save(rq *UploadImageRQ) (err error) {
	var file *os.File
	if fuzzy, ok := getFuzzy(rq); ok {
		fileName := fmt.Sprintf("%sauth/%s_%s.%s", rq.RootDir, rq.MbrId, fuzzy, rq.Ext)
		tmpName := fmt.Sprintf("%sauth/%s_%s_%s.%s", rq.RootDir, rq.MbrId, fuzzy, time.Now().Format("20060102150405"), rq.Ext)
		file, err = os.Create(tmpName)
		defer file.Close()
		if err == nil {
			if _, err = io.Copy(file, bytes.NewBuffer(rq.Data)); err == nil {
				err = os.Rename(tmpName, fileName)
			} else {
				util.GetLogger().Error("[model-saveimage] - error: %s", err.Error())
			}
		} else {
			util.GetLogger().Error("[model-saveimage] - error: %s", err.Error())
		}
	} else {
		err = fmt.Errorf("fuzzy:%d_%d not exists", rq.Type, rq.Seq)
	}

	return
}

func (u *uploadAuthImgCmd) updateUrl(rq *UploadImageRQ) (url string, err error) {
	var id int64
	var repo data.ImageRepo
	mbrId := rq.MbrId
	if _, _, _, id, err = mbrId.Decode(); err == nil {
		if fuzzy, ok := getFuzzy(rq); ok {
			url = fmt.Sprintf("%sauth/%s_%s.%s?ver=%d", rq.Cdn, mbrId, fuzzy, rq.Ext, time.Now().Nanosecond())
			err = repo.AddPhoto(int(id), url, rq.Type, rq.Seq)
			if err != nil {
				util.GetLogger().Error("[model-updateurlimage] - error: %s", err.Error())
			}
		} else {
			err = fmt.Errorf("fuzzy:%d_%d not exists", rq.Type, rq.Seq)
		}
	} else {
		util.GetLogger().Error("[model-updateurlimage] - error. unexpected mbrId:%s", string(mbrId))
	}
	return
}

func getFuzzy(rq *UploadImageRQ) (string, bool) {
	v, ok := fuzzy_map[fmt.Sprintf("%d_%d", rq.Type, rq.Seq)]
	return v, ok
}

func (ad *uploadAdImgCmd) Exec() (url string, err error) {
	var file *os.File
	fileName := fmt.Sprintf("%d", time.Now().UnixNano())
	if file, err = os.Create(fmt.Sprintf("%sad/%s.%s", ad.RootDir, fileName, ad.Ext)); err == nil {
		if _, err = io.Copy(file, bytes.NewBuffer(ad.Data)); err == nil {
			url = fmt.Sprintf("%sad/%s.%s", ad.Cdn, fileName, ad.Ext)
		}
	}
	file.Close()
	return
}
